package lock;

import java.util.concurrent.atomic.AtomicReference;

/**
 * Created by lizhenyu on 2019/9/23
 *
 * description 自旋锁
 */
class SpinLock {
    // Java中原子（CAS）操作
    // 设置持有自旋锁的线程对象
    private AtomicReference<Thread> owner = new AtomicReference<>();

    /**
     * 加锁函数
     */
    public void lock() {
        Thread cur = Thread.currentThread();

        // lock函数将owner设置为当前线程，并且预测原来的值为空。
        // 循环一直被执行，直至第一个线程调用unlock函数将owner设置为null，第二个线程才能进入临界区。
        // 当有第二个线程调用lock操作时由于owner值不为空，导致循环
        while (!owner.compareAndSet(null, cur)){
            System.out.println(cur.getName() + "等待执行。。。");
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 解锁函数
     */
    public void unLock() {
        Thread cur = Thread.currentThread();
        System.out.println(cur.getName() + " 结束，释放锁");
        // 将owner设置为null，并且预测值为当前线程。
        owner.compareAndSet(cur, null);
    }
}
class Test implements Runnable {
    private static int sum;    //共享变量
    private SpinLock lock;     //自旋锁对象

    private Test(SpinLock lock) {
        this.lock = lock;
    }

    public static void main(String[] args) throws InterruptedException {
        SpinLock lock = new SpinLock();
        for (int i = 0; i < 5; i++) {
            Test test = new Test(lock);
            Thread t = new Thread(test);
            t.start();
        }

        while (sum < 5) {
            // 每1s打印一次结果
            Thread.currentThread().sleep(1000);
            System.out.println(sum);
        }
    }

    @Override
    public void run() {
        this.lock.lock();
        // 设置占锁时长3s
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        sum++;
        this.lock.unLock();
    }
}